#pragma once

class Shader
{
	ID3DXEffect* mEffect;
	std::map<std::string, D3DXHANDLE> mParameters;
	void setValue(const std::string& param, void* value, ui32 size);
	void setValue(D3DXHANDLE param, void* value, ui32 size);
public:
	Shader(ID3DXEffect* pEffect) : mEffect(pEffect) {
	}

	template<class T>
	void setValue(const std::string& param, T& value) {
		setValue(param, &value, sizeof(T));
	}

	template<>
	void setValue<IDirect3DTexture9*>(const std::string& param, IDirect3DTexture9*& tex) {
		mEffect->SetTexture(getParamHandle(param), tex);
	}

	template<>
	void setValue<bool>(const std::string& param, bool& val) {
		ui32 value = (val ? 1 : 0);
		setValue(param, &value, 4);
	}

	template<class T>
	void setValue(D3DXHANDLE handle, T& value) {
		setValue(handle, &value, sizeof(T));
	}

	template<>
	void setValue<Texture*>(D3DXHANDLE handle, Texture*& value) {
		mEffect->SetTexture(handle, *value);
	}

	template<>
	void setValue<IDirect3DTexture9*>(D3DXHANDLE handle, IDirect3DTexture9*& tex) {
		mEffect->SetTexture(handle, tex);
	}

	void setTechnique(ui32 index) {
		mEffect->SetTechnique(mEffect->GetTechnique(index));
	}

	D3DXHANDLE getParamHandle(const std::string& param);

	void doBasicRender(std::function<void ()> fun);

	ID3DXEffect* getEffect() { return mEffect; }
};